{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 预处理工具\n",
    "## 优化器\n",
    "PyTorch常用的优化器都封装在`torch.optim`中。\n",
    "\n",
    "### 随机梯度下降（SGD）:最普通的优化器\n",
    "\n",
    "动量参数momentum一般在`0~1`，为普通SGD的改良版"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 利用imagefoler读取数据，预处理，并且存出\n",
    "\n",
    "from torchvision import transforms, utils\n",
    "from torchvision import datasets\n",
    "import torch\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "my_trans = transforms.Compose([\n",
    "    transforms.RandomResizedCrop(224),\n",
    "    transforms.RandomHorizontalFlip(),\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "train_data = datasets.ImageFolder(\"./data/tprchvision_data\", transform=my_trans)\n",
    "train_loader - data.DataLoader(train_data, batch_size=8, shuffle=True)\n",
    "\n",
    "for i, img im  enumerate(train_loader):\n",
    "    if i == 0:\n",
    "        print(img[1])\n",
    "        fig = plt.figure()\n",
    "        grid = utils.make_grid(img[0])\n",
    "        \n",
    "        plt.imshow(grid.numpy().transpose((1, 2, 0)))\n",
    "        plt.show()\n",
    "        utils.save_image(grid,  \"test01.png\")\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.optim as optim\n",
    "\n",
    "optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)\n",
    "\n",
    "# 向前传播\n",
    "out = model(img)\n",
    "loss = criterion(out, label)\n",
    "\n",
    "# 清空梯度\n",
    "optimizer.zero_grad()\n",
    "\n",
    "# 反向传播\n",
    "loss.backward()\n",
    "\n",
    "# 更新梯度\n",
    "optimizer.step()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 动态修改学习率\n",
    "两种方式，\n",
    "1. 修改`optimizer.params_groups`。\n",
    "2. 新建optimizer，简单，但容易引起使用动量的优化器收敛中的震荡。\n",
    "\n",
    "成分：\n",
    "1. `optimizer.param_groups` 长度为1的list\n",
    "2. `optimizer.param_groups[0]`长度为6的字典，包括权重参数、lr、momentum等参数\n",
    "\n",
    "\n",
    "### 多种优化器比较"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.utils.data as Data\n",
    "import torch.nn.functional as F\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "LR = 0.01\n",
    "BATCH_SIZE = 32\n",
    "EPOCH = 12"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成-1，1之间的一千个数值，然后展成一维\n",
    "x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)\n",
    "\n",
    "# y = x^2 并且增加噪点\n",
    "y = x.pow(2) + 0.1 * torch.normal(torch.zeros(*x.size()))\n",
    "\n",
    "torch_dataset = Data.TensorDataset(x, y)\n",
    "# 构建生成器\n",
    "loader = Data.DataLoader(\n",
    "    dataset=torch_dataset, \n",
    "    batch_size=BATCH_SIZE,\n",
    "    shuffle=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 0.6577],\n",
      "        [ 0.7758],\n",
      "        [ 0.2132],\n",
      "        [-0.2613],\n",
      "        [ 0.8599],\n",
      "        [-0.9399],\n",
      "        [-0.1131],\n",
      "        [ 0.7217],\n",
      "        [ 0.4094],\n",
      "        [ 0.1431],\n",
      "        [ 0.4314],\n",
      "        [-0.2372],\n",
      "        [-0.0350],\n",
      "        [ 0.2973],\n",
      "        [ 0.3514],\n",
      "        [ 0.6657],\n",
      "        [-0.6476],\n",
      "        [-0.8559],\n",
      "        [-0.6977],\n",
      "        [ 0.1491],\n",
      "        [-0.6877],\n",
      "        [-0.1191],\n",
      "        [ 0.8639],\n",
      "        [ 0.7698],\n",
      "        [ 0.0270],\n",
      "        [-0.2893],\n",
      "        [-0.0671],\n",
      "        [-0.1932],\n",
      "        [ 0.6537],\n",
      "        [-0.2012],\n",
      "        [ 0.7137],\n",
      "        [-0.0290]])\n",
      "tensor([[ 0.2954],\n",
      "        [ 0.7513],\n",
      "        [ 0.2008],\n",
      "        [-0.0446],\n",
      "        [ 0.7252],\n",
      "        [ 0.9828],\n",
      "        [ 0.2255],\n",
      "        [ 0.3807],\n",
      "        [ 0.2963],\n",
      "        [-0.1009],\n",
      "        [ 0.0478],\n",
      "        [ 0.0141],\n",
      "        [ 0.0521],\n",
      "        [ 0.0141],\n",
      "        [ 0.1085],\n",
      "        [ 0.4425],\n",
      "        [ 0.5084],\n",
      "        [ 0.8892],\n",
      "        [ 0.2629],\n",
      "        [ 0.1155],\n",
      "        [ 0.3714],\n",
      "        [-0.0277],\n",
      "        [ 0.6684],\n",
      "        [ 0.5825],\n",
      "        [-0.0430],\n",
      "        [ 0.0312],\n",
      "        [-0.0682],\n",
      "        [-0.1062],\n",
      "        [ 0.4448],\n",
      "        [ 0.0436],\n",
      "        [ 0.4455],\n",
      "        [-0.0103]])\n"
     ]
    }
   ],
   "source": [
    "for x in loader:\n",
    "    print(x[0])\n",
    "    print(x[1])\n",
    "    break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Net(torch.nn.Module):\n",
    "    u\"\"\"\n",
    "    构建一个基本的神经网络\n",
    "    \"\"\"\n",
    "    \n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        \n",
    "        self.hidden = torch.nn.Linear(1, 20)\n",
    "        self.predict = torch.nn.Linear(20, 1)\n",
    "        \n",
    "    def  forward(self, x):\n",
    "        x = F.relu(self.hidden(x))\n",
    "        x = self.predict(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "开始测试多种优化器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "net_SGD = Net()\n",
    "net_Momentum = Net()\n",
    "net_RMSProp = Net()\n",
    "net_Adam = Net()\n",
    "\n",
    "nets = [net_SGD, net_Momentum, net_RMSProp, net_Adam]\n",
    "opt_SGD = torch.optim.SGD(net_SGD.parameters(),  lr=LR)\n",
    "opt_Momentum = torch.optim.SGD(net_Momentum.parameters(), lr=LR, momentum=0.9)\n",
    "opt_RMSProp = torch.optim.RMSprop(net_RMSProp.parameters(), lr=LR, alpha=0.9)\n",
    "opt_Adam = torch.optim.Adam(net_Adam.parameters(), lr=LR, betas = (0.9,  0.99))\n",
    "\n",
    "optimizers = [opt_SGD, opt_Momentum, opt_RMSProp, opt_Adam]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 开始训练\n",
    "loss_func = torch.nn.MSELoss()\n",
    "loss_his = [[], [], [], []]  # 记录损失\n",
    "\n",
    "for epoch in range(EPOCH):\n",
    "    for step, (batch_x, batch_y) in enumerate(loader):\n",
    "        for net, opt, l_his in zip(nets, optimizers, loss_his):\n",
    "            output = net(batch_x)   # get output for every net\n",
    "            loss = loss_func(output, batch_y)   # compute loss for every net\n",
    "            opt.zero_grad()\n",
    "            loss.backward()   # backpropagation, compuate gradients\n",
    "            opt.step()   # apply gradients\n",
    "            l_his.append(loss.data.numpy())\n",
    "\n",
    "# loss recoder\n",
    "label = [\"SGD\", \"Momentum\", \"RMSprop\", \"Adam\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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PNtWdh+LTyw+fPjw4RNLK/Cqbmw293LA97H48OHDB/jEkhHuBEkDAeFBIH5UmA8f3ysEAgFGjx7N8OHDOeWUU6ipqQGgsrISIQS/+93vzG2rqqoIhUJcffXVACxdupSJEycyevRohg4dylVXXbUnLmGPwSeWDHA0+kKYXSMVLye9bwrz4eN7hdzcXObMmcOCBQsoKyvjkUceMdf169fPrHoM8MILLziSG6+99lquv/565syZw+LFi7nmmmuyPq+U0lGqZV+ETywZYPexYC/p4kksvinMh4/vKw4++GA2bLBq6Obl5TF06FCMxOupU6dy7rnnmus3bdpEz55WURGjHMyTTz7JaaedxsSJExk0aBC33347oKmg/fbbj0suuYThw4ezbt06fvWrXzF8+HBGjBjB1KlTAa10zBFHHMFJJ53Efvvtx49//OO9koT26rL5ewPsisVAQKRRLH64sQ8f7Y57ZtzDkh1L2vWYQ8qGcMP4G7LaNplM8uGHH3LllVc6lk+ZMoXnnnuOLl26EAgE6N69Oxs3bgTg+uuvZ9KkSRxyyCEcd9xxXH755ZSUlAAwY8YMFixYQF5eHuPGjeOkk06iU6dOLF++nKeeeooJEybw0ksvMWfOHObOnUtVVRXjxo3jiCOOMPdftGgRffr0YfLkybz88sucffbZ7E3wFUsGOFoTS7IwhfnE4sPH9wXNzc2MHj2arl27smXLFrPEvYHJkyfz/vvv89xzz3Heeec51l1++eUsXryYc845h48//pgJEyYQjUYBOPbYYykvLyc3N5czzzyTzz//HIA+ffowYcIEQCvJf/755xMIBOjSpQtHHnkkM2fOBGD8+PH079+fQCDA+eefb+6/N8FXLBlgN4XZS7oYS0+K3mXb2jeF+fDREchWWbQ3DB9LU1MTxx9/PI888oijGGU4HGbMmDE88MADLFq0iGnTpjn27969O1dccQVXXHEFw4cPZ8ECrcOHcEWVGu/z8/OzGle6/fcm+IolA1JaE9t63gOskZ1tG/utiX34+D4iLy+PP//5zzzwwAMpvUx+8YtfcM8991BWVuZY/s4775gtiDdv3sz27dvp0UMr1v7++++zY8cOmpubefXVVzn00ENTznn44YczdepUkskk27Zt49NPP2X8+PGAZgpbvXo1qqoydepUDjvssI647F2CTywZYI8KA6ye93qi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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "for i, l_his in enumerate(loss_his):\n",
    "    plt.plot(l_his, label=label[i])\n",
    "\n",
    "plt.legend(loc=\"best\")\n",
    "plt.xlabel(\"Steps\")\n",
    "plt.ylabel(\"Loss\")\n",
    "plt.ylim((0, 0.2))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## utils.data\n",
    "\n",
    "主要包括`Dataset`和`DataLoader`，其中`torch.utils.data.Dataset`为抽象类，自定义数据需要继承这两个类并且实现两个函数`__len__`和`__getitem__`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(tensor([2, 1]), tensor(0))\n",
      "5\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from torch.utils import data\n",
    "import numpy as np\n",
    "\n",
    "class TestDataset(data.Dataset):\n",
    "    def __init__(self):\n",
    "        # 一些由2维向量表示的数据集\n",
    "        self.Data = np.asarray([[1, 2], [3, 4], [2, 1], [3, 4], [4, 5]])\n",
    "        \n",
    "        # 对应的标签\n",
    "        self.Label = np.asarray([0, 1, 0, 1, 2])\n",
    "        \n",
    "    def __getitem__(self, index):\n",
    "        txt = torch.from_numpy(self.Data[index])\n",
    "        label = torch.tensor(self.Label[index])\n",
    "        \n",
    "        return txt, label\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self.Data)\n",
    "    \n",
    "    \n",
    "Test = TestDataset()\n",
    "print(Test[2])\n",
    "print(Test.__len__())\n",
    "print(len(Test))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "DataLoader顾名思义是加载不同数据的生成器\n",
    "\n",
    "```python\n",
    "data.DataLoader(\n",
    "    dataset,                                # 数据集\n",
    "    batch_size = 1,                         # 批次大小\n",
    "    suffule=True,                           # 是否打乱数据\n",
    "    sampler=None,                           # 如何抽样\n",
    "    num_workers=0,                          # 使用多少进程加载数据\n",
    "    collate_Fn=<function default_collate>,  # 将多个样本数据拼成一个batch的方法\n",
    "    pin_memory=False,                       # 是否保存在pin memory区，通常转换到GPU会更快\n",
    "    drop_last=False,                        # 是否将后续凑不齐一个整数batch_size的数据丢弃\n",
    "    timeout=0,\n",
    "    worker_init_fn=None\n",
    ")\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i:  0\n",
      "data:  tensor([[1, 2],\n",
      "        [3, 4]])\n",
      "Label:  tensor([0, 1])\n",
      "i:  1\n",
      "data:  tensor([[2, 1],\n",
      "        [3, 4]])\n",
      "Label:  tensor([0, 1])\n",
      "i:  2\n",
      "data:  tensor([[4, 5]])\n",
      "Label:  tensor([2])\n"
     ]
    }
   ],
   "source": [
    "test_loader = data.DataLoader(Test, batch_size=2, shuffle=False, num_workers = 2)\n",
    "\n",
    "for i, traindata in enumerate(test_loader):\n",
    "    print(\"i: \", i)\n",
    "    Data, Label = traindata\n",
    "    print(\"data: \", Data)\n",
    "    print(\"Label: \",  Label)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## torchvision\n",
    "\n",
    "共有4个模块，\n",
    "- `model`\n",
    "- `datasets`：下载经典数据集\n",
    "- `transforms`：对源数据进行预处理等\n",
    "- `utils`\n",
    "\n",
    "### transforms\n",
    "#### 1. 对PIL Image的操作\n",
    "- `Scale/Resize`：调整比例，长宽比不变\n",
    "- `CenterCrop`、`RandomCrop`、`RandomSizedCrop`：裁剪图片\n",
    "- `Pad`：填充\n",
    "- `ToTensor`：把一个趋势范围是[0, 255]的PIL.Image转换成Tensor。\n",
    "    - 形状为[H, W, C]的`numpy.ndarray`转换成[C, H, W]。\n",
    "    - 取值范围为[0, 1.0]\n",
    "- `RandomHorizontalFlip`：图像随机水平翻转，翻转概率为0.5\n",
    "- `RandomVerticalFlip`：图像随机垂直翻转\n",
    "- `ColorJitter`：修改亮度、对比度和饱和度\n",
    "\n",
    "#### 2. 对Tensor的常见操作\n",
    "- `Normalize`：标准化，(v - mean) / sd\n",
    "- `ToPILImage`：将tensor转化成PIL Image\n",
    "\n",
    "多个操作可以使用`Compose`串联\n",
    "\n",
    "```python\n",
    "transforms.Compose([\n",
    "    transforms.CenterCrop(10),  \n",
    "    # 将PIL.Image进行中心切割，得到给定的大小，size可是tuple(height, width)，也可以是int ->一个正放心\n",
    "    \n",
    "    transforms.RandomCrop(20, padding=0),  \n",
    "    #  切割中心点的位置随机选取\n",
    "    \n",
    "    transforms.ToTensor(),\n",
    "    \n",
    "    transforms.Normalize(mean = (0.5, 0.5, 0.5), std = (0.5, 0.5, 0.5)) \n",
    "    # 规范化到[-1, -1]\n",
    "])\n",
    "```\n",
    "\n",
    "详情可参考[official website](https://pytorch.org/docs/stable/torchvision/transforms.html)\n",
    "\n",
    "### ImageFolder\n",
    "当文件依据标签处于不同文件夹下时\n",
    "可以利用`torchvision.datasets.ImageFolder`来直接构造出dataset\n",
    "\n",
    "- data\n",
    "    - person1\n",
    "        - 001.png\n",
    "        - 002.png\n",
    "    - person2\n",
    "        - 001.png\n",
    "        - 002.png\n",
    "\n",
    "\n",
    "```python\n",
    "loader = datasets.ImageFolder(path)\n",
    "loader = data.DataLoeadr(dataset)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 利用imagefoler读取数据，预处理，并且存出\n",
    "\n",
    "from torchvision import transforms, utils\n",
    "from torchvision import datasets\n",
    "import torch\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "my_trans = transforms.Compose([\n",
    "    transforms.RandomResizedCrop(224),\n",
    "    transforms.RandomHorizontalFlip(),\n",
    "    transforms.ToTensor()\n",
    "])\n",
    "\n",
    "train_data = datasets.ImageFolder(\"./data/tprchvision_data\", transform=my_trans)\n",
    "train_loader - data.DataLoader(train_data, batch_size=8, shuffle=True)\n",
    "\n",
    "for i, img im  enumerate(train_loader):\n",
    "    if i == 0:\n",
    "        print(img[1])\n",
    "        fig = plt.figure()\n",
    "        grid = utils.make_grid(img[0])\n",
    "        \n",
    "        plt.imshow(grid.numpy().transpose((1, 2, 0)))\n",
    "        plt.show()\n",
    "        utils.save_image(grid,  \"test01.png\")\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 可视化工具 tensorboardX\n",
    "\n",
    "tensorboardX功能很强大，支持scalar、image、figure、histogram、audio、text、graph、onnx_graph、embedding、pr_curve and videosummaries等可视化方式。安装也比较方便，先安装tensorflow（CPU或GPU版），然后安装tensorboardX，在命令行运行以下命令即可。\n",
    "\n",
    "#### 1. 基础用法\n",
    "```bash\n",
    "pip install tensorboradX\n",
    "pip install tensorboard\n",
    "```\n",
    "\n",
    "\n",
    "```python\n",
    "from tensorboardX import SummaryWriter\n",
    "\n",
    "writer = SummaryWriter(log_dir='logs')\n",
    "writer.add_xxx(tag-name, object, iteration-number)\n",
    "writer.close()\n",
    "```\n",
    "\n",
    "```bash\n",
    "cd /path/to/parent/of/logs\n",
    "\n",
    "tensorboard --logdir=logs --port 6006 --host 0.0.0.0\n",
    "```\n",
    "\n",
    "#### 2. 可视化graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torchvision\n",
    "from tensorboardX import SummaryWriter\n",
    "\n",
    "\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        \n",
    "        self.conv1 = nn.Conv2d(1, 10, kernel_size = 5)\n",
    "        self.conv2 = nn.Conv2d(10, 20, kernel_size = 5)\n",
    "        self.conv2_drop = nn.Dropout2d()\n",
    "        \n",
    "        self.fc1 = nn.Linear(320, 50)\n",
    "        self.fc2 = nn.Linear(50, 10)\n",
    "        self.bn = nn.BatchNorm2d(20)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = F.max_pool2d(self.conv1(x), 2)\n",
    "        x = F.relu(x) + F.relu(-x)\n",
    "        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))\n",
    "        x = self.bn(x)\n",
    "        x = x.view(-1, 320)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = F.dropout(x, training=self.training)\n",
    "        x =  self.fc2(x)\n",
    "        x = F.softmax(x, dim=1)\n",
    "        return x\n",
    "    \n",
    "input = torch.rand(32, 1, 28, 28)\n",
    "\n",
    "model =  Net()\n",
    "with SummaryWriter(log_dir=\"logs\", comment=\"Net\") as w:\n",
    "    w.add_graph(model, (input, ))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3. 可视化损失值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "dtype = torch.FloatTensor\n",
    "\n",
    "writer = SummaryWriter(log_dir=\"logs\", comment=\"Linear\")\n",
    "np.random.seed(100)\n",
    "\n",
    "x_train = np.linspace(-1, 1, 100).reshape(100, 1)\n",
    "y_train = 3*np.power(x_train, 2) + 2 + 0.2 * np.random.rand(x_train.size).reshape(100, 1)\n",
    "\n",
    "input_size = 1\n",
    "output_size = 100\n",
    "learning_rate = 0.001\n",
    "num_epoches = 5\n",
    "\n",
    "model = nn.Linear(input_size, output_size)\n",
    "criterion = nn.MSELoss()\n",
    "\n",
    "optimizer = torch.optim.SGD(model.parameters(),  lr = learning_rate)\n",
    "\n",
    "for epoch in range(num_epoches):\n",
    "    inputs = torch.from_numpy(x_train).type(dtype)\n",
    "    targets = torch.from_numpy(y_train).type(dtype)\n",
    "    \n",
    "    output = model(inputs)\n",
    "    loss = criterion(output, targets)\n",
    "    optimizer.zero_grad()\n",
    "    optimizer.step()\n",
    "    \n",
    "    writer.add_scalar('训练损失值', loss, epoch)\n",
    "    \n",
    "writer.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4. 可视化特征图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torchvision.utils as vutils\n",
    "\n",
    "writer = SummaryWriter(log_dir=\"logs\", comment=\"feature map\")\n",
    "img_grid = vutils.make_grid(x, normalized=True, scale_each=True, nrow=2)\n",
    "\n",
    "net.eval()\n",
    "\n",
    "for name, layer in net._moudules.items():\n",
    "    # 为fc层预处理x\n",
    "    x = x.view(x.size(0), -1) if \"fc\" in name else x\n",
    "    print(x.size())\n",
    "    x = layer(x)\n",
    "    \n",
    "    print(f\"{name}\")\n",
    "    # 查看卷积层的特征图\n",
    "    if \"layer\" in name or \"conv\" in name:\n",
    "        x1 = x.transpose(0, 1) # C, B, H, W -> B, C, H, W\n",
    "        img_grid = vutils.make_grid(x1, normalize=True, scale_each=True, nrow=4) # nromalzied归一化处理\n",
    "        writer.add_image(f\"{name}_feature_maps\", img_grid, global_step=0)\n",
    "\n",
    "writer.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
